using MultiAgentsClient.ChatDataStructures;
using System.Text.Json;
using System.Reflection;
using MultiAgentsShared;

namespace MultiAgentsServer.Scripts.Database;

public class DatabaseTable : SerializableObjectBase
{
    protected readonly Exception dbException = new("Database operation error.");

    public DatabaseTable() { }
    public DatabaseTable(Dictionary<string, object> row)
    {
        foreach (PropertyInfo prop in GetType().GetProperties())
        {
            if (row[prop.Name] != null)
            {
                object? value;
                if (row[prop.Name] == DBNull.Value)
                {
                    if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        var listType = typeof(List<>).MakeGenericType(prop.PropertyType.GetGenericArguments()[0]);
                        value = Activator.CreateInstance(listType);
                    }
                    else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
                    {
                        var dictType = typeof(Dictionary<,>).MakeGenericType(prop.PropertyType.GetGenericArguments());
                        value = Activator.CreateInstance(dictType);
                    }
                    else
                    {
                        value = null;
                    }
                }
                else
                {
                    if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        Type itemType = prop.PropertyType.GetGenericArguments()[0];
                        Type listType = typeof(List<>).MakeGenericType(itemType);
                        value = JsonSerializer.Deserialize(Convert.ToString(row[prop.Name]) ?? "", listType) ?? Activator.CreateInstance(listType);
                    }
                    else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
                    {
                        Type keyType = prop.PropertyType.GetGenericArguments()[0];
                        Type valueType = prop.PropertyType.GetGenericArguments()[1];
                        Type dictType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
                        value = JsonSerializer.Deserialize(Convert.ToString(row[prop.Name]) ?? "", dictType) ?? Activator.CreateInstance(dictType);
                    }
                    else if (prop.PropertyType.IsEnum)
                    {
                        int intValue = Convert.ToInt32(row[prop.Name]);
                        value = Enum.ToObject(prop.PropertyType, intValue);
                    }
                    else
                    {
                        value = Convert.ChangeType(row[prop.Name], prop.PropertyType);
                    }
                }

                prop.SetValue(this, value);
            }
        }
    }
}

public class ManagerUserDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private string? _name;
    public string Name
    {
        get => _name ?? throw dbException;
        set => _name = value;
    }

    private string? _password;
    public string Password
    {
        get => _password ?? throw dbException;
        set => _password = value;
    }

    private string? _salt;
    public string Salt
    {
        get => _salt ?? throw dbException;
        set => _salt = value;
    }

    private string? _invitationCode;
    public string InvitationCode
    {
        get => _invitationCode ?? throw dbException;
        set => _invitationCode = value;
    }

    public ManagerUserDB() : base() { }
    public ManagerUserDB(Dictionary<string, object> row) : base(row) { }
}

public class UserDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private string? _name;
    public string Name
    {
        get => _name ?? throw dbException;
        set => _name = value;
    }

    private string? _password;
    public string Password
    {
        get => _password ?? throw dbException;
        set => _password = value;
    }

    private string? _salt;
    public string Salt
    {
        get => _salt ?? throw dbException;
        set => _salt = value;
    }

    private string? _avatarUrl;
    public string AvatarUrl
    {
        get => _avatarUrl ?? throw dbException;
        set => _avatarUrl = value;
    }

    private DateTime? _lastLoginTime;
    public DateTime LastLoginTime
    {
        get => _lastLoginTime ?? throw dbException;
        set => _lastLoginTime = value;
    }

    private int? _selectedChatRoomId;
    public int SelectedChatRoomId
    {
        get => _selectedChatRoomId ?? throw dbException;
        set => _selectedChatRoomId = value;
    }

    private int? _selectedProjectId;
    public int SelectedProjectId
    {
        get => _selectedProjectId ?? throw dbException;
        set => _selectedProjectId = value;
    }

    private List<string>? _accessChatModels;
    public List<string> AccessChatModels
    {
        get => _accessChatModels ?? throw dbException;
        set => _accessChatModels = value;
    }

    private List<string>? _accessWorkflowModels;
    public List<string> AccessWorkflowModels
    {
        get => _accessWorkflowModels ?? throw dbException;
        set => _accessWorkflowModels = value;
    }

    private bool? _allowToolCall;
    public bool AllowToolCall
    {
        get => _allowToolCall ?? throw dbException;
        set => _allowToolCall = value;
    }

    public UserDB() : base() { }
    public UserDB(Dictionary<string, object> row) : base(row) { }
}

public class ProjectDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private string? _name;
    public string Name
    {
        get => _name ?? throw dbException;
        set => _name = value;
    }

    private string? _setting;
    public string? Setting
    {
        get => _setting;
        set => _setting = value;
    }

    private DateTime? _createTime;
    public DateTime CreateTime
    {
        get => _createTime ?? throw dbException;
        set => _createTime = value;
    }

    private DateTime? _refreshTime;
    public DateTime RefreshTime
    {
        get => _refreshTime ?? throw dbException;
        set => _refreshTime = value;
    }

    public enum ProjectStatus
    {
        Unarchived,
        Archived,
        Delete,
    }

    private ProjectStatus? _status;
    public ProjectStatus Status
    {
        get => _status ?? throw dbException;
        set => _status = value;
    }

    private int? _userId;
    public int UserId
    {
        get => _userId ?? throw dbException;
        set => _userId = value;
    }

    public ProjectDB() : base() { }
    public ProjectDB(Dictionary<string, object> row) : base(row) { }
}

public class ChatRoomDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private string? _name;
    public string Name
    {
        get => _name ?? throw dbException;
        set => _name = value;
    }

    private bool? _aiRenamed;
    public bool AIRenamed
    {
        get => _aiRenamed ?? throw dbException;
        set => _aiRenamed = value;
    }

    private int? _projectId;
    public int ProjectId
    {
        get => _projectId ?? throw dbException;
        set => _projectId = value;
    }

    private int? _lastMessageId;
    public int LastMessageId
    {
        get => _lastMessageId ?? throw dbException;
        set => _lastMessageId = value;
    }

    public enum ChatRoomStatus
    {
        Unarchived,
        Archived,
        Delete,
    }

    private ChatRoomStatus? _status;
    public ChatRoomStatus Status
    {
        get => _status ?? throw dbException;
        set => _status = value;
    }

    public ChatRoomDB() : base() { }
    public ChatRoomDB(Dictionary<string, object> row) : base(row) { }
}

public class AgentInstanceDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private int? _chatRoomId;
    public int ChatRoomId
    {
        get => _chatRoomId ?? throw dbException;
        set => _chatRoomId = value;
    }

    private int? _typeId;
    public int TypeId
    {
        get => _typeId ?? throw dbException;
        set => _typeId = value;
    }

    private string? _lLMModel;
    public string LLMModel
    {
        get => _lLMModel ?? throw dbException;
        set => _lLMModel = value;
    }

    private float? _temperature;
    public float Temperature
    {
        get => _temperature ?? throw dbException;
        set => _temperature = value;
    }

    private List<string>? _allowedTools;
    public List<string> AllowedTools
    {
        get => _allowedTools ?? throw dbException;
        set => _allowedTools = value;
    }

    public AgentInstanceDB() : base() { }
    public AgentInstanceDB(Dictionary<string, object> row) : base(row) { }
}

public class AgentTemplateDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private string? _name;
    public string Name
    {
        get => _name ?? throw dbException;
        set => _name = value;
    }

    private int? _userId;
    public int UserId
    {
        get => _userId ?? throw dbException;
        set => _userId = value;
    }

    private string? _lLMModel;
    public string LLMModel
    {
        get => _lLMModel ?? throw dbException;
        set => _lLMModel = value;
    }

    private float? _temperature;
    public float Temperature
    {
        get => _temperature ?? throw dbException;
        set => _temperature = value;
    }

    private List<string>? _allowedTools;
    public List<string> AllowedTools
    {
        get => _allowedTools ?? throw dbException;
        set => _allowedTools = value;
    }

    private string? _presetMessage;
    public string PresetMessage
    {
        get => _presetMessage ?? throw dbException;
        set => _presetMessage = value;
    }

    public AgentTemplateDB() : base() { }
    public AgentTemplateDB(Dictionary<string, object> row) : base(row) { }
}

public class MessageDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private int? _userId;
    public int UserId
    {
        get => _userId ?? throw dbException;
        set => _userId = value;
    }

    private int? _agentId;
    public int AgentId
    {
        get => _agentId ?? throw dbException;
        set => _agentId = value;
    }

    private string? _role;
    public string Role
    {
        get => _role ?? throw dbException;
        set => _role = value;
    }

    private string? _author;
    public string Author
    {
        get => _author ?? throw dbException;
        set => _author = value;
    }

    private string? _content;
    public string Content
    {
        get => _content ?? throw dbException;
        set => _content = value;
    }

    // id, name
    private Dictionary<int, string>? _imageList;
    public Dictionary<int, string> ImageList
    {
        get => _imageList ?? throw dbException;
        set => _imageList = value;
    }

    // id, name
    private Dictionary<int, string>? _textFileList;
    public Dictionary<int, string> TextFileList
    {
        get => _textFileList ?? throw dbException;
        set => _textFileList = value;
    }

    private List<int>? _historyMessagesIdList;
    public List<int> HistoryMessagesIdList
    {
        get => _historyMessagesIdList ?? throw dbException;
        set => _historyMessagesIdList = value;
    }

    private string? _toolCallId;
    public string ToolCallId
    {
        get => _toolCallId ?? throw dbException;
        set => _toolCallId = value;
    }
    public bool IsToolCallResponse()
    {
        return _toolCallId != null;
    }

    private int? _chatRoomId;
    public int ChatRoomId
    {
        get => _chatRoomId ?? throw dbException;
        set => _chatRoomId = value;
    }

    private DateTime? _time;
    public DateTime Time
    {
        get => _time ?? throw dbException;
        set => _time = value;
    }

    private string? _toolCalls;
    public string ToolCalls
    {
        get => _toolCalls ?? throw dbException;
        set => _toolCalls = value;
    }

    public MessageDB() : base() { }
    public MessageDB(Dictionary<string, object> row) : base(row) { }
}

public class SystematicNotificationsDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private int? _userId;
    public int UserId
    {
        get => _userId ?? throw dbException;
        set => _userId = value;
    }

    private int? _subscriptionId;
    public int SubscriptionId
    {
        get => _subscriptionId ?? throw dbException;
        set => _subscriptionId = value;
    }

    private Dictionary<string, string>? _content;
    public Dictionary<string, string> Content
    {
        get => _content ?? throw dbException;
        set => _content = value;
    }

    private int? _isProcessed;
    public int IsProcessed
    {
        get => _isProcessed ?? throw dbException;
        set => _isProcessed = value;
    }

    public SystematicNotificationsDB() : base() { }
    public SystematicNotificationsDB(Dictionary<string, object> row) : base(row) { }
}

public class UserSubscriptionsDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private int? _isActive;
    public int IsActive
    {
        get => _isActive ?? throw dbException;
        set => _isActive = value;
    }

    private int? _userId;
    public int UserId
    {
        get => _userId ?? throw dbException;
        set => _userId = value;
    }

    private int? _workflowId;
    public int WorkflowId
    {
        get => _workflowId ?? throw dbException;
        set => _workflowId = value;
    }

    private string? _address;
    public string Address
    {
        get => _address ?? throw dbException;
        set => _address = value;
    }

    private SubscriptionClass? _class;
    public SubscriptionClass Class
    {
        get => _class ?? throw dbException;
        set => _class = value;
    }

    private int? _shouldAskMe;
    public int ShouldAskMe
    {
        get => _shouldAskMe ?? throw dbException;
        set => _shouldAskMe = value;
    }

    public UserSubscriptionsDB() : base() { }
    public UserSubscriptionsDB(Dictionary<string, object> row) : base(row) { }
}

public class WorkflowDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private int? _ownerId;
    public int OwnerId
    {
        get => _ownerId ?? throw dbException;
        set => _ownerId = value;
    }

    private string? _name;
    public string Name
    {
        get => _name ?? throw dbException;
        set => _name = value;
    }

    private string? _workflowJson;
    public string WorkflowJson
    {
        get => _workflowJson ?? throw dbException;
        set => _workflowJson = value;
    }

    public WorkflowDB() : base() { }
    public WorkflowDB(Dictionary<string, object> row) : base(row) { }
}

public class FilesDB : DatabaseTable
{
    private int? _id;
    public int Id
    {
        get => _id ?? throw dbException;
        set => _id = value;
    }

    private string? _fileName;
    public string FileName
    {
        get => _fileName ?? throw dbException;
        set => _fileName = value;
    }

    private string? _content;
    public string Content
    {
        get => _content ?? throw dbException;
        set => _content = value;
    }

    public FilesDB() : base() { }
    public FilesDB(Dictionary<string, object> row) : base(row) { }
}